#pragma once
namespace graph_basic
{
   namespace details
   {
      typedef vertex_t * vertex_raw_iterator_t;
      typedef details::edge_real_t * edge_raw_iterator_t;
   }

struct vertex_iterator_t;
struct edge_iterator_t;
struct adj_edges_iterator_t;
struct adj_vertices_iterator_t;

typedef std::pair<vertex_iterator_t, vertex_iterator_t> vertex_iterator_pair_t;
typedef std::pair<edge_iterator_t, edge_iterator_t> edge_iterator_pair_t;
typedef std::pair<adj_edges_iterator_t, adj_edges_iterator_t> adj_edges_iterator_pair_t;
typedef std::pair<adj_vertices_iterator_t, adj_vertices_iterator_t> adj_vertices_iterator_pair_t;

template<>
struct graph_traits<graph_t>
{
   typedef vertex_iterator_t vertex_iterator;
   typedef edge_iterator_t edge_iterator;
   typedef adj_vertices_iterator_t adj_vertices_iterator;
   typedef adj_edges_iterator_t adj_edges_iterator;
};

struct vertex_iterator_t: std::forward_iterator_tag
{
   void operator ++ ();
   vertex_t  const & operator * () const;
   vertex_t& operator * ();
   bool operator != (vertex_iterator_t const & right) const;
   bool operator == (vertex_iterator_t const & right) const;
private:
   vertex_iterator_t(graph_t & graph)
      :  it_(&graph[0])
   {}
   vertex_iterator_t(details::vertex_raw_iterator_t it)
      :  it_(it)
   {}
   details::vertex_raw_iterator_t it_;
   friend vertex_iterator_pair_t vertices(graph_t& g);
   friend struct edge_iterator_t;
};

struct edge_iterator_t: std::forward_iterator_tag
{
   void operator ++ ();
   edge_t const operator * () const;
   edge_t operator * ();
   bool operator != (edge_iterator_t const & right) const;
   bool operator == (edge_iterator_t const & right) const;
private:
   edge_iterator_t(graph_t& graph)
      :  graph_(&graph)
      ,  cur_v_it_(&graph[0])
      ,  end_v_it_(&graph[0] + graph.get_vertex_count())
      ,  it_(graph.get_vertex_edges(0).first)
      ,  it_end_(graph.get_vertex_edges(0).second)
   {}
   edge_iterator_t(details::edge_raw_iterator_t it)
      :  it_(it)
      ,  cur_v_it_(0)
      ,  end_v_it_(0)
   {}
   vertex_iterator_t cur_v_it_;
   vertex_iterator_t end_v_it_;
   details::edge_raw_iterator_t it_;
   details::edge_raw_iterator_t it_end_;
   graph_t const* graph_;
   friend edge_iterator_pair_t edges(graph_t& g);
};


struct adj_edges_iterator_t: std::forward_iterator_tag
{
   void operator ++ ();
   edge_t const operator * () const;
   edge_t operator * ();
   bool operator != (adj_edges_iterator_t const & right) const;
   bool operator == (adj_edges_iterator_t const & right) const;
private:
   adj_edges_iterator_t(vertex_id_t source_v_id, graph_t& g)
      :  source_v_id_(source_v_id)
      ,  it_(g.get_vertex_edges(source_v_id.vertex_in_graph_id_).first)
   {}
   adj_edges_iterator_t(details::edge_raw_iterator_t it)
      :  it_(it)
   {}
   details::edge_raw_iterator_t it_;
   vertex_id_t source_v_id_;
   friend adj_edges_iterator_pair_t adj_edges(vertex_id_t source_v_id, graph_t& g);
};

struct adj_vertices_iterator_t: std::forward_iterator_tag
{
   void operator ++ ();
   vertex_t const & operator * () const;
   vertex_t& operator * ();
   bool operator != (adj_vertices_iterator_t const & right) const;
   bool operator == (adj_vertices_iterator_t const & right) const;
private:
   adj_vertices_iterator_t(vertex_id_t id, graph_t& g)
      :  it_(g.get_vertex_edges(id.vertex_in_graph_id_).first)
      ,  g_(&g)
   {}
   adj_vertices_iterator_t(details::edge_raw_iterator_t it)
      :  it_(it)
   {}
   details::edge_raw_iterator_t it_;
   graph_t* g_;
   friend adj_vertices_iterator_pair_t adj_vertices(vertex_id_t source_v_id, graph_t& g);
};



vertex_iterator_pair_t vertices(graph_t& g);
edge_iterator_pair_t edges(graph_t& g);
adj_edges_iterator_pair_t adj_edges(vertex_id_t source_v_id, graph_t& g);
adj_vertices_iterator_pair_t adj_vertices(vertex_id_t source_v_id, graph_t& g);
}